#encoding=utf8
'''
Created on 2021年1月16日

@author: clive1158
'''
import cv2,time,os,random
import numpy as np
from cv2 import line

def imshow(img,name='img'):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def is_vertical(line):
    return line[0]==line[2]

def is_horizontal(line):
    return line[1]==line[3]

def overlapping_filter(lines, sorting_index): 
    filtered_lines = [] 
    lines = sorted(lines, key=lambda lines: lines[sorting_index]) 
    for i in range(len(lines)): 
        l_curr = lines[i] 
        if(i>0): 
            l_prev = lines[i-1] 
            if ( (l_curr[sorting_index] - l_prev[sorting_index]) > 5):
                filtered_lines.append(l_curr)
        else:
            filtered_lines.append(l_curr)
    return filtered_lines

def get_Canny_test():
    cv2.namedWindow('Result')
    img = cv2.imread('image/t3.png')
    
    v1 = 0
    v2 = 0
    
    def doEdges():
        edges = cv2.Canny(img,v1,v2)
        edges = cv2.cvtColor(edges,cv2.COLOR_GRAY2BGR)
        res = np.concatenate((img,edges),axis = 0)
        cv2.imshow('Result',edges)
    def setVal1(val):
        global v1
#         cv2.imshow('img',img)
        v1 = val
        doEdges()
    def setVal2(val):
        global v2
        v2 = val
        doEdges()
    
    cv2.createTrackbar('Val1','Result',0,500,setVal1)
    cv2.createTrackbar('Val2','Result',0,500,setVal2)
    
    cv2.imshow('Result',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows

v1 = 0
v2 = 0
def get_lines_test():
    cv2.namedWindow('Result')
    img = cv2.imread('image/t3.png')
    
    img = cv2.resize(img,(800,800))
    
    def doEdges():
        rho = 1  #累加器的距离分辨率
        theta = np.pi/180  #弧度
        theshold = v1    #阈值参数
        minLinLength = 10  #最小线段长度
        maxLineGap = v2  #最大间隙
        print(theta,v1,v2)
        linesP = cv2.HoughLinesP(edges,rho,theta,theshold,None,minLinLength,maxLineGap)
        print(len(linesP))
        
        horizontal_lines = []
        vertical_lines = []
        for i in range(len(linesP)):
            l = linesP[i][0]
            if is_horizontal(l):
                horizontal_lines.append(l)
            if is_vertical(l):
                vertical_lines.append(l)
        
        horizontal_lines = overlapping_filter(horizontal_lines, 1)
        vertical_lines = overlapping_filter(vertical_lines, 0)
        
        cImg = img.copy()
        for i,line in enumerate(horizontal_lines):
            cv2.line(cImg,(line[0],line[1]),(line[2],line[3]),(255,0,0),1,cv2.LINE_AA)
        for i,line in enumerate(vertical_lines):
            cv2.line(cImg,(line[0],line[1]),(line[2],line[3]),(0,0,255),1,cv2.LINE_AA)
        
        cv2.imshow('Result',cImg)
    def setVal1(val):
        global v1
        print(v1)
        v1 = val
        doEdges()
    def setVal2(val):
        global v2
        v2 = val
        doEdges()
    
    cv2.createTrackbar('Val1','Result',0,500,setVal1)
    cv2.createTrackbar('Val2','Result',0,500,setVal2)
    
    edges = cv2.Canny(img,0,150)
    cv2.imshow('Result',edges)
    cv2.waitKey(0)
    cv2.destroyAllWindows

def hough_line_tool(dst_img):
    rho = 1  #累加器的距离分辨率
    theta = np.pi/180  #弧度
    theshold = 170    #阈值参数
    minLinLength = 2  #最小线段长度
    maxLineGap = 12  #最大间隙
#     print(theta)
    linesP = cv2.HoughLinesP(dst_img,rho,theta,theshold,None,minLinLength,maxLineGap)
    if linesP is None:
        return []
    horizontal_lines = []
    vertical_lines = []
    for i in range(len(linesP)):
        l = linesP[i][0]
        if is_horizontal(l):
            horizontal_lines.append(l)
        if is_vertical(l):
            vertical_lines.append(l)
    
    horizontal_lines = overlapping_filter(horizontal_lines, 1)
    vertical_lines = overlapping_filter(vertical_lines, 0)
    return horizontal_lines

def order_points(pts):
    # 一共4个坐标点
    rect = np.zeros((4, 2), dtype = "float32")

    # 按顺序找到对应坐标0123分别是 左上，右上，右下，左下
    # 计算左上，右下
    s = pts.sum(axis = 1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # 计算右上和左下
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    return rect

def four_point_transform(image, pts):
    # 获取输入坐标点
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    print(tl,tr,br,bl)
    # 计算输入的w和h值
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))

    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))

    # 变换后对应坐标位置
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")

    # 计算变换矩阵
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后结果
    return warped

def pre_image():
    image = cv2.imread(r'image/31.jpg')
    orim = image.copy()
    
#     h,w,c = image.shape
#     print(image.shape)
#     rs_img = cv2.resize(image,None,fx=0.5,fy=0.5)
#     imshow(rs_img)
    
    gray = cv2.cvtColor(orim,cv2.COLOR_BGR2BGRA)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    canny_nimage = cv2.Canny(gray,0,150)
    imshow(canny_nimage)
    
    cv2.imwrite(r'image/t5_0.png',canny_nimage)
    
    cnts = cv2.findContours(canny_nimage.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
    cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
    
    screenCnt = None
    screentCntTemp = None
    # 遍历轮廓
    for c in cnts:
        # 计算轮廓近似
        peri = cv2.arcLength(c, True)
        # C表示输入的点集
        # epsilon表示从原始轮廓到近似轮廓的最大距离，它是一个准确度参数
        # True表示封闭的
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    
        # 4个点的时候就拿出来
        if len(approx) == 4:
            print('----4个顶点坐标-----')
            print(order_points(approx.reshape(4,2)))
            rect_point = order_points(approx.reshape(4,2))
            print(rect_point[2][0] / rect_point[2][1])
            '''表格长宽比，大于0.5，小于1'''
            whp = (rect_point[2][0]-rect_point[0][0]) / (rect_point[2][1]-rect_point[0][1]) 
            if whp < 1 and whp > 0.5:
                if screenCnt is not None:
                    '''如果多个框，则使用最小框（x坐标最大）'''
                    if rect_point[0][0] > screentCntTemp[0][0]:
                        screenCnt = approx
                else:
                    screenCnt = approx
                
                '''保存符合条件的且经过排序的坐标'''
                screentCntTemp = rect_point

        cv2.drawContours(image, [approx], -1, (random.randint(0,255), random.randint(100,255), random.randint(0,255)), 2)
    
    
    print("STEP 2: 获取轮廓")
    cv2.imwrite(r'image/t5_0.png',image)
    cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
    cv2.imwrite(r'image/t5_1.png',image)
    
    screent_cnts = screenCnt.reshape(4, 2)
    print(screent_cnts)
    print(screent_cnts[0][0],screent_cnts[0][1],screent_cnts[1][0],screent_cnts[1][1])
#     screent_cnts = [[(screent_cnts[0][0]-5),(screent_cnts[0][1]-5)],
#                     [(screent_cnts[1][0]+5),(screent_cnts[1][1]+5)]]
    
    n_screent_cnts = order_points(screent_cnts)
    
    
#     n_screent_cnts = np.zeros((4, 2), dtype=np.int)
    n_screent_cnts[0][0] = n_screent_cnts[0][0]-15
    n_screent_cnts[0][1] = n_screent_cnts[0][1]-15
    n_screent_cnts[1][0] = n_screent_cnts[1][0]+15
    n_screent_cnts[1][1] = n_screent_cnts[1][1]-15
    n_screent_cnts[2][0] = n_screent_cnts[2][0]+15
    n_screent_cnts[2][1] = n_screent_cnts[2][1]+15
    n_screent_cnts[3][0] = n_screent_cnts[3][0]-15
    n_screent_cnts[3][1] = n_screent_cnts[3][1]+15
    print(n_screent_cnts)
#     print(n_screent_cnts[0])
#     print(n_screent_cnts[1])
    
    imshow(image)
    
    # 透视变换
    warped = four_point_transform(orim, n_screent_cnts)
    cv2.imwrite(r'image/t5_2.png',warped)
    wrapped_orim = warped.copy()
    
    # 二值处理
    warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
    ref = cv2.threshold(warped, 120, 255, cv2.THRESH_BINARY)[1]
    cv2.imwrite(r'image/t5_3.png',ref)
    
    ref = cv2.GaussianBlur(ref, (5, 5), 0)
    canny_nimage = cv2.Canny(ref,0,150)
    cv2.imwrite(r'image/t5_4.png',canny_nimage)
    
    cnts = cv2.findContours(canny_nimage.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
#     cv2.drawContours(wrapped_orim, cnts, -1, (0, 255, 0), 2)
#     imshow(wrapped_orim)
    cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]

    # 遍历轮廓
    for c in cnts:
        # 计算轮廓近似
        peri = cv2.arcLength(c, True)
        # C表示输入的点集
        # epsilon表示从原始轮廓到近似轮廓的最大距离，它是一个准确度参数
        # True表示封闭的
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    
        # 4个点的时候就拿出来
        if len(approx) == 4:
            screenCnt = approx
            break
    print('screentCnt:',screenCnt)
    print('----')
    print(screenCnt.reshape(4, 2))
    raw_wo = wrapped_orim.copy()
    cv2.drawContours(raw_wo, [screenCnt], -1, (0, 255, 0), 2)
    cv2.imwrite(r'image/t5_5.png',raw_wo)
    cv2.imwrite(r'image/t5_6.png',wrapped_orim)
    
    # 透视变换
#     warped = four_point_transform(wrapped_orim, screenCnt.reshape(4, 2))
#     cv2.imwrite(r'image/t5_6.png',warped)
#     wrapped_orim = warped.copy()
    
if __name__ == '__main__':
    
    pre_image()
#     time.sleep(16)
    
    image = cv2.imread(r'image/t5_6.png')
    print(image.shape)
    image = cv2.resize(image,(1197,1547))
    
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    
#     element = cv2.getStructuringElement(cv2.MARKER_CROSS,(1,1))
#     gray = cv2.erode(gray,element)
    
    element = cv2.getStructuringElement(cv2.MORPH_RECT,(1,1))
    gray = cv2.erode(gray,element)
    
#     gray = cv2.GaussianBlur(gray,(5, 5), 0)
    
    dst = cv2.Canny(gray,100,150,None,3)  ##image,minVal,MaxVal    3-算子大小
#     imshow(dst)
    cimage = image.copy()
    
    ###调整第一波参数： 170，2，12
    rho = 1  #累加器的距离分辨率
    theta = np.pi/180  #弧度
    theshold = 170    #阈值参数
    minLinLength = 20  #最小线段长度
    maxLineGap = 12  #最大间隙
    print(theta)
    linesP = cv2.HoughLinesP(dst,rho,theta,theshold,None,minLinLength,maxLineGap)
    print(len(linesP))
    
    horizontal_lines = []
    vertical_lines = []
    for i in range(len(linesP)):
        l = linesP[i][0]
        if is_horizontal(l):
            horizontal_lines.append(l)
        if is_vertical(l):
            vertical_lines.append(l)
    
    horizontal_lines = overlapping_filter(horizontal_lines, 1)
    vertical_lines = overlapping_filter(vertical_lines, 0)
    print('长度大小：%s'%str(len(horizontal_lines)))
    print(horizontal_lines)
    
    '''保存头部及37个选项文件夹'''                
    options_dir_path = r'image/t5_options/'+str(time.time())
    if os.path.exists(options_dir_path) == False:
        os.mkdir(options_dir_path)
    
    ###开始画横线
    ch,cw,cc = cimage.shape
    pre_line = [0,0,0,0]
    part_head_count = 0
    part_option_hori_start_line = [0,0,0,0]
    '''选项开始线集合'''
    part_option_hori_line = []
    part_option_hori_start_flag = False
    
    temp_img1 = cimage.copy()
    for i,line in enumerate(horizontal_lines):
        '''临时使用'''
        cv2.line(temp_img1,(line[0],line[1]),(line[2],line[3]),(0,205,100),10,cv2.LINE_AA)
        print('y坐标：',line[1])
        '''第一条线若纵坐标小于20，则为边缘线'''
        if line[1] < 20 or line[3] == 0:
            continue
        if pre_line is None or pre_line[1] == 0:
            pre_line = [0,line[1],cw,line[3]]
#             print(pre_line)
            cv2.line(cimage,(0,line[1]),(cw,line[3]),(0,205,0),1,cv2.LINE_AA)
            continue
        print(np.subtract(line[1],pre_line[1]))
        if part_head_count == 0 and np.subtract(line[1],pre_line[1]) >= 130:
#             print(pre_line,np.subtract(line[1],pre_line[1]))
            cv2.line(cimage,(0,line[1]),(cw,line[3]),(255,0,0),1,cv2.LINE_AA)
            part_head_count += 1
            ##截取头部内容，进行识别，号牌号码、车辆类型、使用性质、出厂日期、初次登记日期
            head_image = cimage[pre_line[1]+5:line[3],pre_line[0]+2:cw-5]
            pre_line = [0,line[1],cw,line[3]]
            cv2.imwrite(options_dir_path+'/head.png',head_image)
            part_option_hori_start_line = line
            part_option_hori_start_flag = True
            print('记录part_option_hori_line:',part_option_hori_start_line)
            continue
        if 0 < part_head_count and np.subtract(line[1],pre_line[1]) > 40:
            pre_line = [0,line[1],cw,line[3]]
            '''计算选项横向起始点——start'''
            if part_option_hori_start_flag:
                print(line[1],part_option_hori_start_line,np.subtract(line[1],part_option_hori_start_line[1]))
                if np.subtract(line[1],part_option_hori_start_line[1]) > 220:
                    cv2.line(cimage,(0,line[1]),(cw,line[3]),(0,108,10),10,cv2.LINE_AA)
                    part_head_count += 1
                    part_option_hori_line.append(line)
                    part_option_hori_start_flag = False
                    continue
            '''计算选项横向起始点——end'''
            if len(part_option_hori_line) > 0:
                part_option_hori_line.append(line)
            
            cv2.line(cimage,(0,line[1]),(cw,line[3]),(0,0,105),1,cv2.LINE_AA)
            part_head_count += 1
            continue
    
    cv2.imwrite(r'image/t5_10_temp.png',temp_img1)
        
    imshow(cimage)
#         if part_head_count > 10:
#             cv2.line(cimage,(0,line[1]),(cw,line[3]),(20,100,0),1,cv2.LINE_AA)
    cimage2 = cimage.copy()
    ###开始画竖线
    pre_line = [0,0,0,0]
    pre_x = 0
    part_res_count = 0
    part_option_verti_line = []
    for i,line in enumerate(vertical_lines):
        print(line)
        line_length = np.absolute(line[3] - line[1])
        print('线段长度：',line_length)
        
        if line[1] == 0 or line[3] == 0:
            continue
        if pre_line is None or pre_line[1] == 0:
            pre_x = line[0]
            pre_line = [line[0],line[1],line[2],line[3]]
            cv2.line(cimage2,(line[0],0),(line[2],ch),(0,205,0),10,cv2.LINE_AA)
            continue
        if line_length > 10:
            cv2.line(cimage2,(line[0],0),(line[2],ch),(0,50,200),1,cv2.LINE_AA)
        
        print(np.subtract(line[0],pre_line[0]),np.subtract(line[0],pre_x))
        pre_x = line[0]
        if part_res_count == 0 and np.subtract(line[0],pre_line[0]) > 450:
            pre_line = [line[0],line[1],line[0],line[3]]
            print(pre_line)
            cv2.line(cimage2,(line[0],0),(line[2],ch),(100,0,50),10,cv2.LINE_AA)
            part_res_count += 1
            part_option_verti_line.append(line)
            continue
        if part_res_count == 1:
            pre_line = [line[0],line[1],line[0],line[3]]
            cv2.line(cimage2,(line[0],0),(line[2],ch),(100,0,50),10,cv2.LINE_AA)
            part_res_count += 1
            part_option_verti_line.append(line)
            continue
        if part_res_count == 2 and np.subtract(line[0],pre_line[0]) > 450:
            pre_line = [line[0],line[1],line[0],line[3]]
            cv2.line(cimage2,(line[0],0),(line[2],ch),(100,0,50),10,cv2.LINE_AA)
            part_res_count += 1
            part_option_verti_line.append(line)
            continue
        if part_res_count == 3:
            pre_line = [line[0],line[1],line[0],line[3]]
            cv2.line(cimage2,(line[0],0),(line[2],ch),(100,0,50),10,cv2.LINE_AA)
            part_res_count += 1
            part_option_verti_line.append(line)
            continue
    
    print('-------截取选项-------------')    
    options_pos = []
    option_gap = 0
    for i in range(len(part_option_verti_line)):
        if i == 0 or i == 2:
            for j in range(len(part_option_hori_line)):
                if i < len(part_option_verti_line)-1 and j < len(part_option_hori_line)-1:
                    if option_gap > 0:
                        option_gap -= 1
                        continue
                    if len(options_pos) == 0:
#                         print([part_option_verti_line[i][0],part_option_hori_line[j][1],part_option_verti_line[i+1][0],part_option_hori_line[j+4][1]])
                        options_pos.append([part_option_verti_line[i][0],part_option_hori_line[j][1],part_option_verti_line[i+1][0],part_option_hori_line[j+4][1]]);
                        option_gap = 3
                    elif len(options_pos) == 3 or len(options_pos) == 4:
                        options_pos.append([part_option_verti_line[i][0],part_option_hori_line[j][1],part_option_verti_line[i+1][0],part_option_hori_line[j+2][1]])
                        option_gap = 1
                    else:
                        options_pos.append([part_option_verti_line[i][0],part_option_hori_line[j][1],part_option_verti_line[i+1][0],part_option_hori_line[j+1][1]])
                      
    
    print(os.path.exists(options_dir_path))
    print(options_dir_path)
    count = 1
    for option in options_pos:                
        cv2.rectangle(cimage2,(option[0],option[1]),(option[2],option[3]),(108,15,202),2) 
        option_image = cimage2[option[1]:option[3],option[0]:option[2]]
        cv2.imwrite(options_dir_path+'/t5_10_%d.png'%count,option_image)
        count += 1
        
    print(len(options_pos))    
    imshow(cimage2)
    
    cv2.imwrite(r'image/t5_10_1.png',cimage2)
    
    
    pass